package com.ocm.core.associationType.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;

import com.ocm.core.domain.ClassDefinition;
import com.ocm.core.domain.PropertyDefinition;
import com.ocm.core.domain.PropertyType;
import com.ocm.core.exception.OCMException;
import com.ocm.core.model.ClassInstance;
import com.ocm.core.model.ReferenceValue;
import com.ocm.core.model.ReferenceValue.ITEM_STATUS;
import com.ocm.core.service.AssociationTypeService;
import com.ocm.core.service.JCRService;

public class OneToMultipleServiceImpl implements AssociationTypeService {

   private JCRService jcrService;

   public Object getPropertyValue(Property property) throws OCMException {
      try{
         Value[] values = property.getValues();
         String result = "";
         for (Value value : values){
            result += value.getString() + ",";
         }
         return result;
      }catch (Exception exception){
         throw new OCMException(exception);
      }
   }

   public void processReferenceValue(Node instanceClass, String propertyName, ReferenceValue referenceValue)
         throws OCMException {
      try {
      Value[] currentValues = null;
      if (instanceClass.hasProperty(propertyName)) {
         currentValues = instanceClass.getProperty(propertyName).getValues();
      }
      List<Value> multiValues = new ArrayList<Value>();
      List<Value> newValues = new ArrayList<Value>();
      if (currentValues != null) {
         List<Value> oldMultiValues = Arrays.asList(currentValues);
         multiValues.addAll(oldMultiValues);
      }
      for (int index = 0; index < referenceValue.size(); index++) {
         String nodeUUID = referenceValue.getUUID(0);
         if (referenceValue.getItemStatus(0) == ITEM_STATUS.REMOVE)
            multiValues.remove(getIndex(multiValues, nodeUUID));
         else {
            Value nodeValue = PropertyType.OBJECT.convertValue(jcrService.getNodeId(instanceClass.getSession(),
                  nodeUUID));
            newValues.add(nodeValue);
         }
      }
      multiValues.addAll(newValues);
      Value[] values = multiValues.toArray(new Value[0]);
      instanceClass.setProperty(propertyName, values);
      }catch(Exception e){
         throw new OCMException(e);
      }
   }

   public void setJCRService(JCRService jcrService) {
      this.jcrService = jcrService;
   }

   public Object getPropertyObject(Property property) throws OCMException {
      Object result;
      try {
         result = property.getValues();
      } catch (Exception e) {
         throw new OCMException(e);
      }
      return result;
   }

   private int getIndex(List<Value> values, String nodeId) throws ValueFormatException, IllegalStateException,
         RepositoryException {
      for (int index = 0; index < values.size(); index++) {
         if (nodeId.equals(values.get(index).getString())) {
            return index;
         }
      }
      return -1;
   }

   public Object processClassInstance(Session session, Object propertyValue, long classDef,
         List<PropertyDefinition> filterProperties, int maxItems) throws OCMException {
      try{
         List<ClassInstance> classInstances = new ArrayList<ClassInstance>();
         if (propertyValue != null) {
            Value[] values = (Value[]) propertyValue;
            int length = (maxItems == 0 ? values.length : (values.length < maxItems) ? values.length : maxItems);
            for (int index = 0; (index < length); index++) {
               Value value = (Value) values[index];
               Node nextNode = this.jcrService.getNodeId(session, value.getString());
               Map<PropertyDefinition, Object> propertyValues = this.jcrService.getValues(nextNode,
                     filterProperties);
               ClassInstance classInstance = new ClassInstance();
               ClassDefinition classDefinition = new ClassDefinition();
               classDefinition.setId(classDef);
               classInstance.setClassDefinition(classDefinition);
               classInstance.setProperties(propertyValues);
               classInstance.setNodeUUID(nextNode.getIdentifier());
               classInstance.setNodeName(nextNode.getName());
               classInstance.setRealPath(nextNode.getPath());
               classInstances.add(classInstance);
            }
         }
         return classInstances;
      }catch (Exception exception){
         throw new OCMException(exception);
      }
   }

   public boolean support(Property property) throws OCMException {
      try{
         if (property.isMultiple() && property.getValues() != null && property.getValues().length > 0)
            return true; 
         return false;
      }catch (Exception exception){
         throw new OCMException(exception);
      }
   }

   public void removeReference(Property property, Node removeNode) throws OCMException {
      try{
         Value[] currentValues = property.getValues();
         List<Value> multiValues = new ArrayList<Value>(Arrays.asList(currentValues));
         multiValues.remove(getIndex(multiValues, removeNode.getIdentifier()));
         Value[] values = multiValues.toArray(new Value[0]);
         property.setValue(values);
      }catch (Exception exception){
         throw new OCMException(exception);
      }
   }
}
